package logic

import (
	"crypto/tls"
	"go.uber.org/zap"
	"net/http"
	"strconv"
	"strings"
	"wms/dao/mysql"
	"wms/define"
	"wms/models"
	"wms/pkg/snowflake"
)

// 存放业务逻辑

func GetUserBasic(p *define.ParamUserLogin) (*models.UserBasic, error) {
	ub := new(models.UserBasic)
	tx := mysql.GetUserBasicByUsernamePassword(p.Username, p.Password)
	if err := tx.Find(ub).Error; err != nil {
		zap.L().Error("mysql.GetUserBasicByUsernamePassword find failed", zap.Error(err))
		return nil, err
	}
	return ub, nil
}

func ConfirmOPassword(p *define.ParamUserChangePassword, mc *define.MyClaims) (bool, error) {
	password, err := mysql.GetUserPasswordByIdentity(mc.Identity)
	if err != nil {
		return false, err
	}
	oPassword := define.EncryptMd5(p.OPassword)
	if password != oPassword {
		return false, nil
	}
	return true, nil
}

func UserPasswordChange(p *define.ParamUserChangePassword, mc *define.MyClaims) error {
	return mysql.ChangeUserPassword(mc.Identity, p.Password)
}

// GetUserList 获取用户列表，并返回 keyword 相关的所有用户的数量
func GetUserList(p *define.ParamUserListPage) (int64, []*define.UserListReply, error) {
	var userListCnt int64
	userLists := make([]*define.UserListReply, 0)
	tx := mysql.GetUserListByKeyword(p.Keyword)
	err := tx.Count(&userListCnt).Offset((p.Page - 1) * p.Size).Limit(p.Size).Find(&userLists).Error
	if err != nil {
		zap.L().Error("mysql.GetUserListByKeyword count failed", zap.Error(err))
		return 0, nil, err
	}

	for _, v := range userLists {
		v.CreatedAt = define.RFC3339ToNormalTime(v.CreatedAt)
		v.UpdatedAt = define.RFC3339ToNormalTime(v.UpdatedAt)
	}

	return userListCnt, userLists, err
}

// CreateUser 创建用户
func CreateUser(p *define.ParamUserAdd) error {
	var userCnt int64
	tx := mysql.GetUserBasicByUsername(p.Username)
	if err := tx.Count(&userCnt).Error; err != nil {
		zap.L().Error("mysql.GetUserBasicByUsername count failed", zap.Error(err))
		return err
	}

	if userCnt > 0 {
		// 存在该用户名的用户
		return define.MysqlErrorUsernameExist
	}

	ub := &models.UserBasic{
		Identity:     strconv.FormatUint(snowflake.GetUint64ID(), 10),
		Username:     p.Username,
		Password:     define.EncryptMd5(p.Password),
		Phone:        p.Phone,
		RoleIdentity: p.RoleIdentity,
	}
	return mysql.InsertOneUser(ub)
}

// UpdateUser 更新用户
func UpdateUser(p *define.ParamUser) error {
	// 1. 更新后，用户名不能重复
	var ubCnt int64
	tx := mysql.GetUserBasicByUsername(p.Username).Where("identity != ?", p.Identity)
	if err := tx.Count(&ubCnt).Error; err != nil {
		zap.L().Error("mysql.GetUserBasicByUsername count failed", zap.Error(err))
		return err
	}

	if ubCnt > 0 {
		// 用户名已存在
		zap.L().Warn("UpdateUser failed", zap.String("error", define.MysqlErrorUsernameExist.Error()))
		return define.MysqlErrorUsernameExist
	}

	// 2. 组装数据
	ub := &models.UserBasic{
		Identity:     p.Identity,
		Username:     p.Username,
		Phone:        p.Phone,
		RoleIdentity: p.RoleIdentity,
	}

	// 3. 前端没传密码，就默认不更新
	if p.Password == "" {
		return mysql.UpdateUserByIdentityWithoutPassword(ub)
	} else {
		ub.Password = define.EncryptMd5(p.Password)
		return mysql.UpdateUserByIdentity(ub)
	}
}

// DeleteUser 删除用户
func DeleteUser(identity string) error {
	return mysql.DeleteUserByIdentity(identity)
}

// GetUserDetail 获取用户详情
func GetUserDetail(identity string, p *define.UserDetailReply) error {
	tx := mysql.GetUserBasicByIdentity(identity)
	if err := tx.Find(p).Error; err != nil {
		zap.L().Error("mysql.GetUserBasicByIdentity find failed", zap.Error(err))
		return err
	}

	p.CreatedAt = define.RFC3339ToNormalTime(p.CreatedAt)
	p.UpdatedAt = define.RFC3339ToNormalTime(p.UpdatedAt)
	return nil
}

// UpdateUserAvatar 修改用户头像
func UpdateUserAvatar(identity string, p *define.ParamAvatar) error {
	err := func() error {
		// 1. 测试头像链接是否可访问

		// 跳过对服务端证书有效性的验证，客户端不会验证服务器提供证书是否由可信任机构签发，以及服务端证书中主机名是否与请求主机名匹配
		// 否则报错（TLS证书验证失败）：x509: certificate signed by unknown authority
		tr := &http.Transport{
			TLSClientConfig: &tls.Config{
				InsecureSkipVerify: true,
			},
		}
		// 自定义 http 客户端，使用自定义 Transport：控制 HTTP 客户端行为的结构体，可配置代理、TLS连接信息
		client := &http.Client{
			Transport: tr,
		}
		resp, err := client.Head(p.Avatar)
		if err != nil {
			zap.L().Error("client.Head error", zap.Error(err))
			return err
		}
		defer resp.Body.Close()
		// 2. 判断链接是否是一个图片
		contentType := resp.Header.Get("Content-Type")
		if !strings.HasPrefix(contentType, "image") {
			zap.L().Error("Content-Type Not has image prefix", zap.Error(define.UserErrorAvatarNotImage))
			return define.UserErrorAvatarNotImage
		}
		return nil
	}()
	if err != nil {
		return err
	}
	return mysql.UpdateUserAvatarByIdentity(identity, p.Avatar)
}
